package com.ooolong.expression;

import java.util.LinkedList;
import java.util.List;
import java.util.Stack;

import com.ooolong.expression.operator.Operator;

public class ExpressionTree {

	private String expression;
	private ONode root;

	public ExpressionTree(ONode root) {
		this.root = root;
	}

	public void build(String expression) {
		this.expression = expression;
		List<OObject> ooList = parse(this.expression);

		for (OObject oo : ooList) {

		}
	}

	private void findMinPrecedenceItem(ONode parent, List<OObject> ooList, int start, int end) {
		int lastPrecedence = -1;
		int index = -1;
		int lastLeftParenthesis = 0;
		for (int i = start; i < end; i++) {
			OObject obj = ooList.get(i);
			if (obj instanceof ONumber || obj.getType() == OObject.STRING) {
				continue;
			}
			if (obj instanceof Operator) {
				int precedence = ((Operator) obj).getPrecedence();
				if (lastPrecedence == -1) {
					lastPrecedence = precedence;
				}
				if (precedence < lastPrecedence) {
					lastPrecedence = precedence;
					index = i;
				}
			}
			
			if (obj.getType() == OObject.LEFT_PARENTHESIS) {
				lastLeftParenthesis++;
			}
			if (obj.getType() == OObject.RIGHT_PARENTHESIS) {
			}
		}
	}

	private List<OObject> parse(String s) {
		LinkedList<OObject> ooList = new LinkedList<OObject>();
		Stack<Character> quoteStack = new Stack<Character>();
		StringBuffer buf = new StringBuffer();
		for (int i = 0; i < s.length(); i++) {
			char c = s.charAt(i);
			if (isClosedPathSign(c)) {
				OObject oobject = OObject.newInstance(OObject.newClosedPathSymbol(c));
				OClosedPathSymbol closedPathSymbol = (OClosedPathSymbol) oobject;
				if (closedPathSymbol.getType() == OObject.LEFT_PARENTHESIS) {
					if (buf.toString().trim().length() > 0 && quoteStack.empty()) {
						ooList.add(OObject.newInstance(OObject.newFunctionName(buf.toString())));
						buf.setLength(0);
					}
				} else if (closedPathSymbol.getType() == OObject.RIGHT_PARENTHESIS) {
					if (buf.toString().trim().length() > 0 && quoteStack.empty()) {
						ooList.add(OObject.newInstance(toNumber(buf.toString())));
						buf.setLength(0);
					}
				}
				ooList.add(closedPathSymbol);
				continue;
			}

			if (isMathOperator(c)) {
				if (buf.toString().trim().length() > 0 && quoteStack.empty()) {
					Number number = toNumber(buf.toString());
					ooList.add(OObject.newInstance(number));
					buf.setLength(0);
				}
				ooList.add(OObject.newInstance(OObject.newOperatorSymbol(c + "")));
				continue;
			}

			if (isLogicOperatorChar(c)) {
				if (buf.toString().trim().length() > 0 && quoteStack.empty()) {
					Number number = toNumber(buf.toString());
					ooList.add(OObject.newInstance(number));
					buf.setLength(0);
				}
				String operator = "" + c;
				char next = s.charAt(i + 1);
				if (isLogicOperatorChar(next)) {
					operator += next;
					i++;
				}
				ooList.add(OObject.newInstance(OObject.newOperatorSymbol(operator)));
				continue;
			}

			if (c == '\'') {
				if (!quoteStack.isEmpty()) {
					char lastQuote = quoteStack.peek();
					if (lastQuote == c) {
						ooList.add(OObject.newInstance(buf.toString()));
						buf.setLength(0);
						quoteStack.pop();
					}
				} else {
					quoteStack.push(c);
				}
				continue;
			} else {
				buf.append(c);
			}
		}

		if (buf.length() > 0) {
			Number number = toNumber(buf.toString());
			ooList.add(OObject.newInstance(number));
		}
		return ooList;
	}

	private Number toNumber(String s) {
		s = s.trim();
		if (s.indexOf('.') > 0) {
			return Double.parseDouble(s);
		}
		return Long.parseLong(s);
	}

	public static final char[] CLOSED_PATH_SIGN = { '(', ')', '[', ']', '{', '}' };
	public static final char[] MATH_OPERATOR = { '+', '-', '*', '/', '%' };
	public static final String[] LOGIC_OPERATOR = { "=", ">", "<", "!=", "==", ">=", "<=" };

	private boolean isClosedPathSign(char c) {
		return isLeftClosedPathSign(c) || isRightClosedPathSign(c);
	}

	private boolean isLeftClosedPathSign(char c) {
		return c == '(' || c == '[' || c == '{';
	}

	private boolean isRightClosedPathSign(char c) {
		return c == ')' || c == ']' || c == '}';
	}

	private boolean isMathOperator(char c) {
		for (int i = 0; i < MATH_OPERATOR.length; i++) {
			if (MATH_OPERATOR[i] == c) {
				return true;
			}
		}
		return false;
	}

	private boolean isLogicOperatorChar(char c) {
		if (c == '=' || c == '=' || c == '>' || c == '<' || c == '!') {
			return true;
		}
		return false;
	}

	private boolean isLogicOperator(String operator) {
		for (int i = 0; i < LOGIC_OPERATOR.length; i++) {
			if (LOGIC_OPERATOR[i].equals(operator)) {
				return true;
			}
		}
		return false;
	}

	public static void main(String[] args) {
		ExpressionTree etree = new ExpressionTree(null);
		etree.build("4 * (3 * 5 - 2 + 1)");
		System.out.println();
		etree.build("\'abc123\'");
	}
}
